package com.wwj.study.zookeeper.lock;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;

import java.io.IOException;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @Author: wuweijun
 * @Date: 2019/1/11 15:02
 */
public class DistributedLock implements Lock, Watcher {

    private ZooKeeper zooKeeper;
    //根节点
    private String ROOT_NODE="/zookeeper-lock";
    //当前获取锁节点
    private String CURRENT_NODE="";
    //下一个等待获取锁节点
    private String WAIT_NODE="";

    CountDownLatch countDownLatch;

    public DistributedLock(){
        try {
            zooKeeper=new ZooKeeper("172.30.1.172:2181",4000,this);
            Stat stat= zooKeeper.exists(ROOT_NODE,false);
            if(stat==null){
                zooKeeper.create(ROOT_NODE,"0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void lock() {
        if(this.tryLock()){
            System.out.println(Thread.currentThread().getName()+" 获取锁成功 "+CURRENT_NODE);
            return;
        }

        //继续等待锁
        try {
            waitForLock(WAIT_NODE);
        } catch (KeeperException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private boolean waitForLock(String prev) throws KeeperException, InterruptedException {
        //开启监听
        Stat stat=zooKeeper.exists(prev,true);
        if(stat!=null) {
            System.out.println(Thread.currentThread().getName() + " 等待锁 " + prev+" 释放");
            countDownLatch = new CountDownLatch(1);
            countDownLatch.await();

            System.out.println(Thread.currentThread().getName() + " 获取锁成功");
        }

        return true;
    }

    public void lockInterruptibly() throws InterruptedException {

    }

    public boolean tryLock() {

        //创建临时有序节点
        try {
            CURRENT_NODE = zooKeeper.create(ROOT_NODE+"/","0".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
            System.out.println(Thread.currentThread().getName()+" 尝试竞争锁:"+CURRENT_NODE);

            //获取根节点下面的所有子节点
            List<String> childrens= zooKeeper.getChildren(ROOT_NODE,false);
            SortedSet<String> sortedSet=new TreeSet<String>();
            for (String children:childrens){
                sortedSet.add(ROOT_NODE+"/"+children);
            }
            String firstNode=sortedSet.first();
            SortedSet<String> lessThenMe=((TreeSet<String>) sortedSet).headSet(CURRENT_NODE);

            if(CURRENT_NODE.equals(firstNode)){
                return true;
            }

            //子节点中，还存在其他节点
            if(!lessThenMe.isEmpty()){
                //获取下一个节点，作为等待锁节点
                WAIT_NODE=lessThenMe.last();
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;
    }

    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return false;
    }

    public void unlock() {
        try {
            zooKeeper.delete(CURRENT_NODE,-1);
            CURRENT_NODE=null;
            zooKeeper.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (KeeperException e) {
            e.printStackTrace();
        }
    }

    public Condition newCondition() {
        return null;
    }

    public void process(WatchedEvent event) {
        if(countDownLatch !=null){
            countDownLatch.countDown();
        }

    }
}
